#pragma once

#include <string>
#include <cstring>
#include <iostream>
#include <fstream>
#include <unordered_map>
#include <unordered_set>
#include <vector>
#include <gmp.h>
#include <gmpxx.h>
#include <assert.h>
#include "json.hpp"
#include "zuc.h"
#include "sha256.h"

std::string hex2string(const char*, size_t);
void string2hex(std::string, char*, size_t);
int char2num(char);

template <typename T>
class Singleton {
 public:
  static T& Instance();
  Singleton(const Singleton&) = delete;
  Singleton& operator=(const Singleton&) = delete;
 private:
  Singleton() = default;
  ~Singleton() = default;
};
template <typename T>
T& Singleton<T>::Instance() {
  static T instance;
  return instance;
}

class PRF {
private:
    unsigned char key[32];
    int resultLength;
    SHA256 hashFunc;
    ZUC zuc;
public:
    PRF() = default;
    PRF(mpz_class k, int len): resultLength(len) {
        assert((len & 3) == 0);
        hashFunc(k.get_str());
        hashFunc.getHash(key);
        hashFunc.reset();
    }
    void setup(mpz_class k, int len) {
        assert((len & 3) == 0);
        resultLength = len;
        hashFunc(k.get_str());
        hashFunc.getHash(key);
        hashFunc.reset();
    }
    void operator() (const void *data, size_t dataLen, char* result);
    std::string operator()(std::string);
};
class PiePrf: public PRF {};
class FPrf: public PRF {};
class PPrf: public PRF {};

std::string SKE_Enc(mpz_class key, std::string m_data);
std::string SKE_Dec(mpz_class key, std::string c_data);

struct Node {
    std::string data;
    Node* right;
    Node* down;
    Node(std::string str): data(str), right(nullptr), down(nullptr) {}
};

struct ST {
    int n_;  // 关键词个数
    int N_;  // 文件个数
    Node** Lw;
    Node** Lf;
    ST(int n, int N): n_(n), N_(N) {
        Lw = new Node*[n + 1];
        Lf = new Node*[N + 1];
    }
    ST(): n_(0), N_(0) {}
    void setup(int n, int N) {
        n_ = n;
        N_ = N;
        Lw = new Node*[n + 1];
        Lf = new Node*[N + 1];
    }
    ST(const ST&) = delete;
    ST& operator=(const ST&) = delete;
    // ~ST() { }
};

